﻿#region License

// Created by John Batte on 04/15/2012 at 7:48 PM.
// Last code cleanup: 04/15/2012 at 7:48 PM.
// 
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// 
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
// 
// You should have received a copy of the GNU General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.

#endregion

using System;
using System.Collections.Generic;
using System.Text;

using BatteCode.Fx.RegularExpressions;

namespace BatteCode.Google.Wiki.Logic
{
	/// <summary>
	/// Defines wiki helper extensions.
	/// </summary>
	public static class WikiHelperExtensions
	{
		private static readonly CompiledRegex _whitespace = @"\s+";

		private static readonly IDictionary<HeadingLevel, Func<string, string>> _headings
			= new Dictionary<HeadingLevel, Func<string, string>>
			{
				{ HeadingLevel.One, s => String.Format(WikiString.HeadingFormatLevel1, s) },
				{ HeadingLevel.Two, s => String.Format(WikiString.HeadingFormatLevel2, s) },
				{ HeadingLevel.Three, s => String.Format(WikiString.HeadingFormatLevel3, s) },
				{ HeadingLevel.Four, s => String.Format(WikiString.HeadingFormatLevel4, s) },
				{ HeadingLevel.Five, s => String.Format(WikiString.HeadingFormatLevel5, s) },
				{ HeadingLevel.Six, s => String.Format(WikiString.HeadingFormatLevel6, s) }
			};

		/// <summary>
		/// Creates a revision link.
		/// </summary>
		/// <param name="helper">The helper.</param>
		/// <param name="revisionNumber">The revision number.</param>
		/// <returns></returns>
		public static WikiString RevisionLink(this IWikiHelper helper, int revisionNumber)
		{
			return new WikiString(String.Format(WikiString.RevisionFormat, revisionNumber));
		}

		/// <summary>
		/// Creates an issue link.
		/// </summary>
		/// <param name="helper">The helper.</param>
		/// <param name="issueNumber">The issue number.</param>
		/// <returns></returns>
		public static WikiString IssueNumber(this IWikiHelper helper, int issueNumber)
		{
			return new WikiString(String.Format(WikiString.IssueFormat, issueNumber));
		}

		/// <summary>
		/// Prevents the specified text from auto-linking.
		/// </summary>
		/// <param name="helper">The helper.</param>
		/// <param name="text">The text.</param>
		/// <returns></returns>
		public static WikiString NoLink(this IWikiHelper helper, string text)
		{
			return new WikiString(String.Format(WikiString.NoLinkFormat, text));
		}

		/// <summary>
		/// Creates a wiki link to the specified page.
		/// </summary>
		/// <param name="helper">The helper.</param>
		/// <param name="pageName">Name of the page.</param>
		/// <param name="text">The text.</param>
		/// <param name="heading">The heading (optional).</param>
		/// <returns></returns>
		public static WikiString Link(this IWikiHelper helper, string pageName, string text = null, string heading = null)
		{
			string linkText = String.IsNullOrEmpty(text) ? String.Empty : String.Format(WikiString.WikiLinkTextFormat, text);
			string headingText = String.IsNullOrEmpty(heading) ? String.Empty : String.Format(WikiString.WikiLinkHeadingFormat, HeadingName(heading));
			return new WikiString(String.Format(WikiString.WikiLinkFormat, pageName, headingText, linkText));
		}

		/// <summary>
		/// Creates a heading using the specified text.
		/// </summary>
		/// <param name="helper">The helper.</param>
		/// <param name="text">The text.</param>
		/// <param name="headingLevel">The heading level.</param>
		/// <returns></returns>
		public static WikiString Heading(this IWikiHelper helper, string text, HeadingLevel headingLevel = HeadingLevel.One)
		{
			return !_headings.ContainsKey(headingLevel) ? WikiString.Empty : new WikiString(_headings[headingLevel](text));
		}

		/// <summary>
		/// Removes all formatting from the specified text.
		/// </summary>
		/// <param name="helper">The helper.</param>
		/// <param name="text">The text.</param>
		/// <returns></returns>
		public static WikiString PlainText(this IWikiHelper helper, string text)
		{
			return new WikiString(String.Format(WikiString.PlainTextFormat, text));
		}

		/// <summary>
		/// Strikes out the specified text.
		/// </summary>
		/// <param name="helper">The helper.</param>
		/// <param name="text">The text.</param>
		/// <returns></returns>
		public static WikiString StrikeOut(this IWikiHelper helper, string text)
		{
			return new WikiString(String.Format(WikiString.StrikeOutFormat, text));
		}

		/// <summary>
		/// Sub-scripts the specified text.
		/// </summary>
		/// <param name="helper">The helper.</param>
		/// <param name="text">The text.</param>
		/// <returns></returns>
		public static WikiString SubScript(this IWikiHelper helper, string text)
		{
			return new WikiString(String.Format(WikiString.SubScriptFormat, text));
		}

		/// <summary>
		/// Super-scripts the specified text.
		/// </summary>
		/// <param name="helper">The helper.</param>
		/// <param name="text">The text.</param>
		/// <returns></returns>
		public static WikiString SuperScript(this IWikiHelper helper, string text)
		{
			return new WikiString(String.Format(WikiString.SuperScriptFormat, text));
		}

		/// <summary>
		/// Wraps the specified text as a code item.
		/// </summary>
		/// <param name="helper">The helper.</param>
		/// <param name="text">The text.</param>
		/// <returns></returns>
		public static WikiString Code(this IWikiHelper helper, string text)
		{
			return new WikiString(String.Format(WikiString.CodeFormat, text));
		}

		/// <summary>
		/// Wraps the specified text as a code block.
		/// </summary>
		/// <param name="helper">The helper.</param>
		/// <param name="text">The text.</param>
		/// <returns></returns>
		public static WikiString CodeBlock(this IWikiHelper helper, string text)
		{
			return new WikiString(String.Format(WikiString.CodeBlockFormat, text));
		}

		/// <summary>
		/// Wraps the specified text as a code block with a specified language.
		/// </summary>
		/// <param name="helper">The helper.</param>
		/// <param name="language">The language.</param>
		/// <param name="text">The text.</param>
		/// <returns></returns>
		public static WikiString CodeWithLanguage(this IWikiHelper helper, string language, string text)
		{
			return new WikiString(String.Format(WikiString.CodeLanguageFormat, language, text));
		}

		/// <summary>
		/// Creates a labels directive using the specified labels.
		/// </summary>
		/// <param name="helper">The helper.</param>
		/// <param name="labels">The labels.</param>
		/// <returns></returns>
		public static WikiString Labels(this IWikiHelper helper, params string[] labels)
		{
			string labelText = String.Join(",", labels);
			return new WikiString(String.Format(WikiString.LabelsFormat, labelText));
		}

		/// <summary>
		/// Bolds the specified text.
		/// </summary>
		/// <param name="helper">The helper.</param>
		/// <param name="text">The text.</param>
		/// <returns></returns>
		public static WikiString Bold(this IWikiHelper helper, string text)
		{
			return new WikiString(String.Format(WikiString.BoldFormat, text));
		}

		/// <summary>
		/// Italicizes the specified text.
		/// </summary>
		/// <param name="helper">The helper.</param>
		/// <param name="text">The text.</param>
		/// <returns></returns>
		public static WikiString Italics(this IWikiHelper helper, string text)
		{
			return new WikiString(String.Format(WikiString.ItalicsFormat, text));
		}

		/// <summary>
		/// Creates a sidebar directive using the specified name.
		/// </summary>
		/// <param name="helper">The helper.</param>
		/// <param name="sidebarName">Name of the sidebar.</param>
		/// <returns></returns>
		public static WikiString Sidebar(this IWikiHelper helper, string sidebarName)
		{
			return new WikiString(String.Format(WikiString.SideBarFormat, sidebarName));
		}

		/// <summary>
		/// Creates a summary header. Summary text is normalized to one line; that is, any contiguous whitespace blocks (including line breaks) are converted to a single space.
		/// </summary>
		/// <param name="helper">The helper.</param>
		/// <param name="summary">The summary.</param>
		/// <returns></returns>
		public static WikiString Summary(this IWikiHelper helper, string summary)
		{
			string normalizedSummary = _whitespace.Replace(summary, " ");
			return new WikiString(String.Format(WikiString.SummaryFormat, normalizedSummary));
		}

		/// <summary>
		/// Creates a bullet point at the specified indent level (default = zero).
		/// </summary>
		/// <param name="helper">The helper.</param>
		/// <param name="text">The text.</param>
		/// <param name="indentLevel">The indent level (default = zero).</param>
		/// <returns></returns>
		public static WikiString Bullet(this IWikiHelper helper, string text, int indentLevel = 0)
		{
			var indent = new string(' ', indentLevel + 1);
			StringBuilder bulletBuilder = new StringBuilder(indent).Append(WikiString.BulletListItem).Append(text);
			return new WikiString(bulletBuilder.ToString());
		}

		/// <summary>
		/// Creates a numbered item at the specified indent level (default = zero).
		/// </summary>
		/// <param name="helper">The helper.</param>
		/// <param name="text">The text.</param>
		/// <param name="indentLevel">The indent level (default = zero).</param>
		/// <returns></returns>
		public static WikiString NumberedItem(this IWikiHelper helper, string text, int indentLevel = 0)
		{
			var indent = new string(' ', indentLevel + 1);
			StringBuilder numberBuilder = new StringBuilder(indent).Append(WikiString.NumberListItem).Append(text);
			return new WikiString(numberBuilder.ToString());
		}

		private static string HeadingName(string heading)
		{
			return _whitespace.Replace(heading, "_").ToLower();
		}
	}
}